
#include "bsp_sgm415xx.h"
#include "i2c2.h"
#include "bsp_uart.h"
#include "i2c_select.h"
#include "systick.h"
#include "bsp_gpio.h"
#include "bsp_sgm41513_i2c.h"
#include "simulation_i2c.h"

#ifdef __BSP_DEBUG__
    #define DEBUG_LOG(format, ...) printf(format, ##__VA_ARGS__)
//    #define BSP_LOG(format, ...)   printf(format, ##__VA_ARGS__)
#else
    #define DEBUG_LOG(format, ...)
#endif



#define COM_I2CM_SCLH   GPIO_SetBit(SCL_GPIO_PORT, SCL_PIN)  // GPIO_SetBits(SGM415XX_SCL_GPIO_PORT, SGM415XX_SCL_GPIO_PIN)   /* Set GPIOn output high */
#define COM_I2CM_SCLL   GPIO_ClearBit(SCL_GPIO_PORT, SCL_PIN)  // GPIO_ResetBits(SGM415XX_SCL_GPIO_PORT, SGM415XX_SCL_GPIO_PIN)    /* Set GPIOn output low  */

#define COM_I2CM_SDAH   GPIO_SetBit(SDA_GPIO_PORT, SDA_PIN)   // GPIO_SetBits(SGM415XX_SDA_GPIO_PORT, SGM415XX_SDA_GPIO_PIN)   /* Set GPIOm output high */
#define COM_I2CM_SDAL   GPIO_ClearBit(SDA_GPIO_PORT, SDA_PIN) // GPIO_ResetBits(SGM415XX_SDA_GPIO_PORT, SGM415XX_SDA_GPIO_PIN)  /* Set GPIOm output low  */

//int get_sda(void) { return 0; }

#define COM_I2CM_SDAR   GPIO_ReadInputBit(SDA_GPIO_PORT, SDA_PIN)  // get_sda() // GPIO_ReadInputDataBit(SGM415XX_SDA_GPIO_PORT, SGM415XX_SDA_GPIO_PIN)  /* Set GPIOm input and get sensor data */


/***************************************************************************************************
 * @fn      delay
 *
 * @brief   延时
 *
 * @param   无
 *
 * @return  无
 */
static void delay(void)
{
	volatile uint8_t time = 20;

	while (time--);
}


/***************************************************************************************************
 * @fn      com_i2cm_strt
 *
 * @brief   主机向从机发送起始信号
 *
 * @param   无 
 *
 * @return  无
 */
static void com_i2cm_strt(void)
{
    COM_I2CM_SDAH;
    COM_I2CM_SCLH;
    delay();
    COM_I2CM_SDAL;
    delay();
    COM_I2CM_SCLL;
}

/***************************************************************************************************
 * @fn      com_i2cm_stop
 *
 * @brief   主机向从机发送停止信号
 *
 * @param   无
 *
 * @return  无
 */
static void com_i2cm_stop(void)
{ 
    COM_I2CM_SDAL;
    COM_I2CM_SCLL;
    delay();
    COM_I2CM_SCLH;
    delay();
    COM_I2CM_SDAH;
}

/***************************************************************************************************
 * @fn      com_i2cm_acks
 *
 * @brief   主机向从机发送应答信号
 *
 * @param   无
 *
 * @return  无
 */
static void com_i2cm_acks(void)
{
    COM_I2CM_SCLL;
    COM_I2CM_SDAL;
    delay();
    COM_I2CM_SCLH;
    delay();
    COM_I2CM_SCLL;
    COM_I2CM_SDAH;
}

/***************************************************************************************************
 * @fn      com_i2cm_nack
 *
 * @brief   主机向从机发送非应答信号
 *
 * @param   无
 *
 * @return  无
 */
static void com_i2cm_nack(void)
{
    COM_I2CM_SCLL;
    COM_I2CM_SDAH;
    delay();
    COM_I2CM_SCLH;
    delay();
    COM_I2CM_SCLL;
}

/***************************************************************************************************
 * @fn      com_i2cm_wait_acks
 *
 * @brief   等待从机的应答信号
 *
 * @param   acks_data 回应的数据
 *
 * @return  无
 */
static void com_i2cm_wait_acks(uint8_t *acks_data)
{
    uint8_t erro_time = 0;

    COM_I2CM_SDAH;
    delay(); 
    COM_I2CM_SCLH;

    while(COM_I2CM_SDAR)
    {
        erro_time++;
        if(erro_time > 100)
        {
            DEBUG_LOG("I2C acknowledge error!\r\n");
            com_i2cm_stop();
            * acks_data = 1;
            return;
        }
    }
    delay();
    COM_I2CM_SCLL;
    *acks_data = 0;
}

/***************************************************************************************************
 * @fn      com_i2cm_writ_byte
 *
 * @brief   向i2c接口写入一个字节数据
 *
 * @param   writ_byte 写入的数据
 *
 * @return  无
 */
static void com_i2cm_writ_byte(uint8_t writ_byte)
{                        
    uint8_t i;       

    for(i = 0; i < 8; i++)
    {   
        if((writ_byte & 0x80) >> 7)
            COM_I2CM_SDAH;
        else
            COM_I2CM_SDAL;
        
        writ_byte = writ_byte << 1;
				
        delay();
        COM_I2CM_SCLH;
        delay(); 
        COM_I2CM_SCLL;
        delay(); 
    }         
}

/***************************************************************************************************
 * @fn      com_i2cm_read_byte
 *
 * @brief   从i2c接口读取一个字节数据
 *
 * @param   无
 *
 * @return  读取到的一个字节数据
 */
static uint8_t com_i2cm_read_byte(void)
{
    uint8_t i;
    uint8_t read_byte = 0;

    for(i = 0; i < 8; i++ )
    {
        COM_I2CM_SCLL; 
        delay();
        COM_I2CM_SCLH;
        delay();
        read_byte = read_byte << 1;
        if(COM_I2CM_SDAR)
        read_byte++;   
        delay();
    }

    return read_byte;
}

/***************************************************************************************************
 * @fn      com_i2cm_sgm415x_8bitwrit
 *
 * @brief   向i2c接口写多个数据
 *
 * @param   slav_addr  器件地址
 * @param   writ_cmmd  写命令
 * @param   numb   写入的数据个数
 * @param   blck_data 数据缓冲区 
 *
 * @return  成功返回TRUE; 失败返回FALSE 
 */
int com_i2cm_sgm415x_8bitwrit(uint8_t slav_addr, uint8_t writ_cmmd, uint8_t numb, uint8_t *blck_data)
{
	uint8_t acks;

    /* Start */  
    com_i2cm_strt();

    /* Slave address (write) */ 
    com_i2cm_writ_byte(slav_addr << 1);
    com_i2cm_wait_acks(&acks);
	if (acks)
	{
		DEBUG_LOG("i2cm write addr ERROR\r\n");
		return FALSE;
	}

	com_i2cm_writ_byte(writ_cmmd);
	com_i2cm_wait_acks(&acks);
	if (acks)
	{
		DEBUG_LOG("i2cm write cmd ERROR\r\n");
		return FALSE;
	}

    while (numb--)
    {
        /* Write data */ 
        if (acks == 0)	
        { 										  		   
            com_i2cm_writ_byte(*blck_data);
			blck_data++;
            com_i2cm_wait_acks(&acks);
        }
        else
        {
			DEBUG_LOG("i2cm write data ERROR\r\n");
            return FALSE;
        }
    }

    /* Stop */ 
    com_i2cm_stop();

	return TRUE;
}

/***************************************************************************************************
 * @fn      com_i2cm_sgm415x_8bitread
 *
 * @brief   从i2c接口读取多个数据 
 *
 * @param   slav_addr  器件地址
 * @param   read_cmmd  读取命令
 * @param   numb  读取的个数
 * @param   blck_data 数据缓冲区 
 *
 * @return  成功返回TRUE; 失败返回FALSE 
 */
int com_i2cm_sgm415x_8bitread(uint8_t slav_addr, uint8_t read_cmmd, uint8_t numb, uint8_t *blck_data)
{
    uint8_t acks;

    /* Start */ 
    com_i2cm_strt();
    
    /* Slave address (write) */ 
    com_i2cm_writ_byte(slav_addr << 1);
    com_i2cm_wait_acks(&acks);
	if (acks)
	{
		DEBUG_LOG("i2cm write addr ERROR\r\n");
		return FALSE;
	}

    /* Command code */ 
	com_i2cm_writ_byte(read_cmmd);
	com_i2cm_wait_acks(&acks);
	if (acks)
	{
		DEBUG_LOG("i2cm write cmd ERROR\r\n");
		return FALSE;
	}

    /* Slave address (read) */  
	com_i2cm_strt(); 
	com_i2cm_writ_byte((slav_addr << 1) + 1);
	com_i2cm_wait_acks(&acks);
	if (acks)
	{
		DEBUG_LOG("i2cm write addr ERROR\r\n");
		return FALSE;
	}

    /* Read data */ 
    while (numb --)
    {
        *blck_data++ = com_i2cm_read_byte();

        if(numb)
            com_i2cm_acks();  /* Acknowledge until read done */
        else
            com_i2cm_nack();	
    }

    /* Stop */ 
    com_i2cm_stop();

    return TRUE;
}

/***************************************************************************************************
 * @fn      bsp_InitI2cGpio
 *
 * @brief   初始化I2C的GPIO
 *
 * @param   无 
 *
 * @return  无 
 */
void bsp_InitI2c_SGM415x(void)
{
    GPIO_Config_T gpioConfig;
    
    RCM_EnableAHBPeriphClock(SCL_GPIO_CLK);
    RCM_EnableAHBPeriphClock(SDA_GPIO_CLK);
    
    gpioConfig.pin     = SCL_PIN;
    gpioConfig.mode    = GPIO_MODE_OUT;
    gpioConfig.outtype = GPIO_OUT_TYPE_OD;
    gpioConfig.speed   = GPIO_SPEED_50MHz;
    gpioConfig.pupd    = GPIO_PUPD_NO;
    GPIO_Config(SCL_GPIO_PORT, &gpioConfig);
    
    gpioConfig.pin     = SDA_PIN;
    gpioConfig.mode    = GPIO_MODE_OUT;
    gpioConfig.outtype = GPIO_OUT_TYPE_OD;
    gpioConfig.speed   = GPIO_SPEED_50MHz;
    gpioConfig.pupd    = GPIO_PUPD_NO;
    GPIO_Config(SDA_GPIO_PORT, &gpioConfig);

    com_i2cm_stop();  
}


